package com.orderplus.opshop.web;

import com.orderplus.opshop.core.constants.enums.SystemConfig;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.MessageSourceResolvable;
import org.springframework.context.NoSuchMessageException;
import org.springframework.ui.context.Theme;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.servlet.support.RequestContextUtils;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.lang.reflect.Method;
import java.util.Locale;
import java.util.Map;

/**
 * Title:
 * Description:
 * Company: Copyright @ 2019 OrderPlus 版权所有
 *
 * @version 1.0 初稿
 * @author: mhj
 * @date: 2019年4月1日下午15:26:06
 */
public final class ApplicationContext implements ApplicationContextAware {

	private ApplicationContext() {
		//Noops
	}

	/**
	 * container
	 */
	private static org.springframework.context.ApplicationContext container;

	/**
	 * web容器
	 */
	private static ServletContext servletContext;


	/**
	 * 获取bean
	 *
	 * @param name
	 * @return Object
	 */
	@SuppressWarnings("unchecked")
	public static <T> T getBean(String name) {
		try {
			return (T) getContainer().getBean(name);
		} catch (Exception e) {
			return null;
		}
	}

	/**
	 * 获取bean
	 *
	 * @param name
	 * @param clz
	 * @return Object
	 */
	public static <T> T getBean(String name, Class<T> clz) {
		return getContainer().getBean(name, clz);
	}

	/**
	 * 获取bean
	 *
	 * @param clz
	 * @return Object
	 */
	public static <T> T getBean(Class<T> clz) {
		return getContainer().getBean(clz);
	}

	/**
	 * 获取WEB应用上下文
	 *
	 * @return ServletContext
	 */
	public static ServletContext getServletContext() {
		return servletContext;
	}

	/**
	 * 设置WEB应用上下文
	 *
	 * @param servletContext
	 */
	public static void setServletContext(ServletContext servletContext) {
		ApplicationContext.servletContext = servletContext;
	}

	/**
	 * 获取当前HTTP请求的Request，只有在HTTP请求线程中调用生效
	 *
	 * @return
	 */
	public static HttpServletRequest getRequest() {
		ServletRequestAttributes attrs = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
		if (null != attrs) {
			return attrs.getRequest();
		}
		return null;
	}

	/**
	 * 获取当前HTTP请求的SESSION，只在HTTP请求线程中生效
	 *
	 * @return
	 */
	public static HttpSession getSession() {
		HttpServletRequest req = getRequest();
		if (null != req) {
			return req.getSession(false);
		}
		return null;
	}

	public static String getMessage(String code, HttpServletRequest request, Object... args) {
		String value = "";
		String languageType = "";
		if (request != null) {
			languageType = request.getParameter("languageType");
		}
		if (StringUtils.isEmpty(languageType)) {
			value = container.getMessage(code, args, Locale.CHINESE);
		} else {
			if (SystemConfig.LanguageTypeEnum.IN.name().equals(languageType)) {
				Locale locale = new Locale(SystemConfig.LanguageTypeEnum.IN.name().toLowerCase(), SystemConfig.CountryCodeEnum.ID.name());
				value = container.getMessage(code, args, locale);
			}
			if (SystemConfig.LanguageTypeEnum.TH.name().equals(languageType)) {
				Locale locale = new Locale(SystemConfig.LanguageTypeEnum.TH.name().toLowerCase(), SystemConfig.CountryCodeEnum.TH.name());
				value = container.getMessage(code, args, locale);
			}
			if (SystemConfig.LanguageTypeEnum.EN.name().equals(languageType)) {
				value = container.getMessage(code, args, Locale.ENGLISH);
			}
			if (SystemConfig.LanguageTypeEnum.ZH.name().equals(languageType)) {
				value = container.getMessage(code, args, Locale.CHINESE);
			}
		}
		return value;
	}

	/**
	 * 获取i18n字符串，如果不存在则原样返回，Locale是采用用户信息中的， 如果不存在，则使用系统默认
	 *
	 * @param code i18n的编码
	 * @return i18n字符串
	 */
	public static String getMessage(String code) {
		return getMessage(code, (Object[]) null);
	}

	/**
	 * 获取i18n字符串，如果不存在则原样返回，Locale是由参数指定.
	 *
	 * @param code   i18n的编码
	 * @param locale 指定的地区信息
	 * @return i18n字符串
	 */
	public static String getMessage(String code, Locale locale) {
		return getMessage(code, null, locale);
	}

	/**
	 * 获取i18n字符串，如果不存在则原样返回，Locale是采用用户信息中的， 如果不存在，则使用系统默认
	 *
	 * @param code i18n的编码
	 * @param args 参数值
	 * @return i18n字符串
	 */
	public static String getMessage(String code, Object[] args) {
		Locale locale = getCurrentUserLocale();
		if (null == locale) {
			// 获取操作系统默认的地区
			locale = Locale.getDefault();
		}
		return getMessage(code, args, code, locale);
	}

	/**
	 * 获取i18n字符串，如果不存在则原样返回，Locale是由参数指定.
	 *
	 * @param code   i18n的编码
	 * @param locale 指定的地区信息
	 * @param args   参数值
	 * @param locale
	 * @return i18n字符串
	 */
	public static String getMessage(String code, Object[] args, Locale locale) {
		return getMessage(code, args, code, locale);
	}

	/**
	 * 获取i18n字符串
	 *
	 * @param code           i18n的编码
	 * @param args           参数值
	 * @param defaultMessage 如果找不到code对应的i18n信息，则使用该默认信息
	 * @param locale         地区编码
	 * @return i18n字符串
	 */
	public static String getMessage(String code, Object[] args, String defaultMessage, Locale locale) {
		if (getContainer() == null) {
			return code;
		}
		try {
			return getContainer().getMessage(code, args, defaultMessage, locale);
		} catch (NoSuchMessageException ex) {
			return code;
		}
	}

	/**
	 * 获取i18n字符串
	 *
	 * @param messagesourceresolvable
	 * @param locale                  地区编码
	 * @return i18n字符串
	 */
	public static String getMessage(MessageSourceResolvable messagesourceresolvable, Locale locale) {
		if (getContainer() == null) {
			return messagesourceresolvable.getDefaultMessage();
		}
		return getContainer().getMessage(messagesourceresolvable, locale);
	}

	public static String getMessage(MessageSourceResolvable messagesourceresolvable) {
		Locale locale = getCurrentUserLocale();
		if (null == locale) {
			// 获取操作系统默认的地区
			locale = Locale.getDefault();
		}
		return getMessage(messagesourceresolvable, locale);
	}

	public static String getMessage(String code, String languageType) {
		return getValue(code, languageType, null);
	}

	private static String getValue(String code, String languageType, Object... args) {
		String value = "";
		if (StringUtils.isEmpty(languageType)) {
			value = container.getMessage(code, args, Locale.ENGLISH);
		} else {
			if (SystemConfig.LanguageTypeEnum.IN.name().equals(languageType)) {
				Locale locale = new Locale(SystemConfig.LanguageTypeEnum.IN.name().toLowerCase(), SystemConfig.CountryCodeEnum.ID.name());
				value = container.getMessage(code, args, locale);
			}
			if (SystemConfig.LanguageTypeEnum.TH.name().equals(languageType)) {
				Locale locale = new Locale(SystemConfig.LanguageTypeEnum.TH.name().toLowerCase(), SystemConfig.CountryCodeEnum.TH.name());
				value = container.getMessage(code, args, locale);
			}
			if (SystemConfig.LanguageTypeEnum.EN.name().equals(languageType)) {
				value = container.getMessage(code, args, Locale.ENGLISH);
			}
			if (SystemConfig.LanguageTypeEnum.ZH.name().equals(languageType)) {
				value = container.getMessage(code, args, Locale.CHINESE);
			}
		}
		return value;
	}

	/**
	 * 获取当前用户的Locale，需要在Servlet环境下使用
	 *
	 * @return 返回当前用户的Locale, 否则返回NULL
	 */
	public static Locale getCurrentUserLocale() {
		Locale locale = null;
		// 尝试获取用户的地区
		HttpServletRequest request = getRequest();
		if (null != request) {
			locale = RequestContextUtils.getLocale(request);
		}
		return locale;
	}

	/**
	 * 获取当前用户的主题，需要在Servlet环境下使用
	 *
	 * @return 返回当前用户的主题，否则返回NULL
	 */
	public static Theme getCurrentUserTheme() {
		Theme theme = null;
		// 尝试获取用户的主题
		HttpServletRequest request = getRequest();
		if (null != request) {
			theme = RequestContextUtils.getTheme(request);
		}
		return theme;
	}

	/**
	 * 设置当前系统使用的container
	 *
	 * @param c
	 */
	public static void setContainer(org.springframework.context.ApplicationContext c) {
		container = c;
	}

	public static synchronized org.springframework.context.ApplicationContext getContainer() {
		if (container == null) {
			ServletContext ctx = ApplicationContext.getServletContext();
			if (ctx != null) {
				container = WebApplicationContextUtils.getRequiredWebApplicationContext(ctx);
			}
		}
		return container;
	}


	public static void publishApplicationEvent(final ApplicationEvent event) {
		if (event != null && getContainer() != null) {
			getContainer().publishEvent(event);
		}
	}

	@Override
	public void setApplicationContext(org.springframework.context.ApplicationContext applicationContext) throws BeansException { //NOSONAR
		container = applicationContext; //NOSONAR
	}

	public static Object invokeMap(String beanName, String methodName, Map<String, Object> ht) throws Exception {
		Object obj = container.getBean(beanName);
		if (obj != null) {
			Method method = obj.getClass().getDeclaredMethod(methodName, Map.class);
			if (method != null) {
				Object o = method.invoke(obj, ht);
				return o;
			}
		}
		return null;
	}

	public static Object invokeString(String beanName, String methodName, String json) throws Exception {
		Object obj = container.getBean(beanName);
		if (obj != null) {
			Method method = obj.getClass().getDeclaredMethod(methodName, String.class);
			if (method != null) {
				Object o = method.invoke(obj, json);
				return o;
			}
		}
		return null;
	}

}
